Chapter 7

 The Macintosh Toolbox*363*

 t Working with the Toolbox
 t Calling Conventions
 t Essential Mac Methods

The Macintosh Toolbox is the collection of low-level routines that implement the Macintosh operating system and user interface.  The Toolbox opens the door to the full range of functionality provided by the Macintosh:  sophisticated color graphics, digital sound, multilingual font support, networking, and so on.  This chapter provides an entrance into using the Macintosh Toolbox from Prograph.

NOTE:  If you are new to programming on the Macintosh, this chapter will only whet your appetite.  Macintosh Revealed by Stephen Chernicoff and How To Write Macintosh Software by Scott Knaster are two excellent places to learn more. The definitive references are Apple’s  Inside Macintosh series and the  Macintosh Technical Notes.

t
Working with the Toolbox*363*

Most of the Macintosh Toolbox calls are accessible from Prograph as Mac Methods. 
Mac Method operations are created in the same way as Prograph primitives. You can create an operation and type in the Mac Method name directly, or you can use the ˙Info… dialog to find and transfer the name.  The interpreter recognizes the name as a Mac Method and properly annotates the operation icon when the return key is pressed.  For example the Macintosh Toolbox call PenSize, which is used to set the width and height of the pen for drawing operations, is shown below.  Mac Methods can be easily identified by the double lines on their top and bottom edges.

 
Mac Method names are exactly as given for Pascal functions and procedures in Inside Macintosh.  Prograph will not let you create a Mac Method with an incorrect name.

QuickDraw is the part of the Toolbox that lets you perform graphic operations.

Working with Pict and Icon Resources*364*

With Prograph’s Application Builder, you can easily create and manage multiple windows on the screen.  Graphics can be displayed in window items of class Icon, Pict, and Canvas. 

All Macintosh files can have both a data fork and a resource fork.  A program’s resources reside in its resource fork and can include many different predefined items, including character fonts, the layout of dialog and alert boxes, chunks of code for window and menu definition functions, icons and pictures, and so on.  In general, the same sorts of resources are used by many different types of programs.  A program’s data fork, however, usually contains information which is specific to that particular application. 

'PICT' resources are displayed using Pict window items and 'ICON' resources are displayed using Icon window items.  Setting the rsrc number attribute of these window items to the resource number of a particular 'ICON' or 'PICT' resource will cause that resource to be displayed in its window item, assuming of course that an 'ICON' or 'PICT' resource of that number exists in the resource fork of the Prograph application file. 

'PICT' and 'ICON' resources can be cut and pasted directly to and from the resource fork of a Prograph application file by way of a selected Pict or Icon object in the WYSIWYG Window editor.  First set the rsrc number attribute of these window items to a number different from that of any existing 'PICT' or 'ICON' resource which may already be in the resource fork of the application file, unless you wish to replace the existing resource with a new one of the same number.  The interaction with the Clipboard is then just the same as cutting and pasting text. 

Alternatively, Apple’s ResEdit program can be used to maintain resources in the Prograph application program’s resource fork.  A discussion of ResEdit is beyond the scope of this manual. 

Drawing in Canvas Items*365*

Canvas window items provide areas in a window to which drawing instructions can be directed.  A wide variety of drawing facilities are provided by the Macintosh Toolbox for creating, measuring and manipulating graphical entities. These include but are not limited to:

o lines of any size and pattern;

o text characters with different sizes, styles, and typefaces;

o regions composed of combinations of lines and shapes forming a closed area;

o shapes such as arcs, circles, polygons, ovals, rectangles, and wedges.

Below is a simple example which shows some of the basics of using a Canvas item.  The user should know how to use the Prograph program editor, the System Classes and the WYSIWYG window editor well enough to be able to:

u Create a window;

u Add it to the Active list;

u Create a Canvas item in the window;

u Give the Canvas a draw method called my draw;

u Give the Canvas a click method called my click;

u Create a Persistent called my rect and give it the value of 0 0 20 20.

Canvas Draw Method*365*

The draw method attribute of a Canvas item contains the name of a method which will be automatically executed whenever the Canvas item needs to be redrawn.  An update event, forcing a redraw, is generated when the Canvas item’s window is first opened, when it is brought to the front from behind other windows or when a new area of the Canvas is made visible by rearranging windows which are in front of it.  Users can also draw directly into a Canvas at any time they wish, using the protocol described below. 

The universal method my draw is the draw method for the new Canvas item and looks like this:

The method has three inputs:  the window which owns the Canvas item, the Canvas item itself and the Macintosh EventRecord for the update event which generated the need to redraw the Canvas.  In my draw none of these inputs are needed. 

NOTE:  Unused inputs on automatically dispatched methods can be deleted.  In this example they have been left because this is the way that Prograph will automatically create the method when the program is run if the user has given a draw method name but has not yet created the method.

Because my draw is designed to be called automatically by Prograph as the draw method for this Canvas item, it is not necessary for the user to call the primitive sc-begin-drawing before starting to draw in the Canvas.  In fact it would be a mistake to do so.  Prograph itself calls sc-begin-drawing before passing control to my draw and it calls sc-end-drawing after my draw has finished its work. 

My draw shows three Macintosh methods. EraseRect paints the given rectangle with the current background pattern.  In a new window this will be set, by default, to white.  This ensures that the Canvas is clear before we begin to draw.  The rectangle given is made very big to ensure that the whole canvas will always be erased. We could calculate the actual size of the visible region of the Canvas but the begin-drawing setup code ensures that any drawing which happens in a Canvas will be clipped to the bounding rectangle of the Canvas. 

NOTE:  A region is a Macintosh data structure which can hold an arbitrarily complex shape or set of shapes.  A window’s invalid region is the area of the window that needs to be redrawn.

Every Prograph window has a clip region which is set by the call to sc-begin-drawing and which is set again to an empty region by the call to sc-end-drawing.  Clipping means that even if a method is called to draw beyond a window’s clip region, nothing will be drawn outside of that region. *367*

When a draw method is automatically dispatched by Prograph, the drawing area is clipped to the intersection of the Canvas bounds and the window’s invalid region.  Users can add areas to a window’s invalid region by using the Toolbox calls InvalRect and InvalRgn to indicate those areas of the Canvas which they want updated.  This procedure helps to reduce flicker caused by redrawing parts of the Canvas which have not changed.  Calling InvalRect or InvalRgn will also post an update event which Prograph will process, causing it to dispatch the draw method of any Canvas item whose bounds intersect the window’s invalid region. 

When a user calls sc-begin-drawing directly, the drawing area is clipped simply to the rectangular bounds of the Canvas item.

PenSize sets both the height and width of the drawing pen to five pixels.  
NOTE:  The default pen state is one pixel wide and high, with a color of black and a mode of patCopy.  In a more complex application, where other drawing may have been happening in other Canvas items in the same window, it may be wise to completely reset the pen with a call to PenNormal before using it.

FrameRect draws a rectangle using a line five pixels wide.  The coordinates of the rectangle come from the Persistent my rect.  The point 0 0 is the top left corner of the the Canvas.  Users can change the Canvas origin if they wish, but in this example we are using the default values.

Note that the three Mac Methods have synchro links so that EraseRect happens before PenSize is set and that PenSize is set before FrameRect is called.

Canvas Click Method *367*

The click method for a Canvas item is automatically called whenever a click event occurs in the Canvas.  The universal method my click has three parts, each encapsulated in a local method.  First the click is examined to determine if it hit the rectangle which was drawn in the Canvas.  If it did not then my click is terminated immediately.  If it did then we allow the user to drag the rectangle’s outline around on the screen.  After that the rectangle is redrawn. 

Now we look at the internals of the three local methods.

The click point is passed in and fed to the Toolbox method PtInRect together with the current position of the rectangle from the persistent my rect.  PtInRect returns TRUE if the point is in the rectangle, FALSE otherwise. If the result is not TRUE, failure is propagated to the calling valid click? local operation in the my click method, terminating execution of my click.

In the do drag local, the primitive drag-rect is fed the Canvas item, the current position of the rectangle, the point that was clicked ( which is now guaranteed to be within the rectangle ) and the Macintosh constant noConstraint, which allows dragging to occur in both horizontal and vertical dimensions. *367*

drag-rect will keep control for as long as the mouse button is held down, and the user will see a gray rectangular outline which will move with the mouse position.  When the mouse button is released the new position of the rectangle is returned and assigned to the persistent my rect.

In the local method do draw the universal method my draw, which was described above, is called.  This time, however, we must explicitly call the primitive  sc-begin-drawing before my draw and sc-end-drawing after it.  We do this because it is us and not Prograph who are calling the draw method.  Therefore it is our responsibility to bracket the draw method with the sc-begin-drawing and sc-end-drawing calls.

If we do not call sc-begin-drawing before my draw, the coordinate system and origin of the Canvas will not be properly adjusted, nor will the window’s clip region be correctly set up.  If we do not call sc-end-drawing after my draw then any drawing that the Prograph interpreter needs to do may be messed up.

Drawing in Windows*369*

Canvas items are the preferred place for drawing to happen when the Prograph System Classes are being used.  However, drawing can still be done directly into a Prograph System Class window.  No automatic dispatch of a draw method or click method is available in a System Class window.  Because there are some occasions when drawing directly into such a window is necessary, the method wind-draw-prep is provided in class Window.

wind-draw-prep expects an instance of class Window or of a sub-class of Window as input. It gets the Macintosh WindowRecord and calls the Toolbox method SetPort.  This makes that window the current GrafPort and ensures that any drawing which is done will be directed to that window.  An in-depth discussion of Macintosh GrafPorts is beyond the scope of this manual.  The user is encouraged to investigate further using the references given at the start of this chapter.

The next section, “Calling Conventions”, provides technical information on Prograph’s interface to the Macintosh Toolbox. The subsequent section, “Essential Mac Methods”, describes a useful subset of the Toolbox calls, emphasizing those related to graphics.*370*

t
Calling Conventions*370*

NOTE:  Some understanding of the Pascal Programming language is necessary to understand what follows.

The Macintosh Toolbox routines use Pascal conventions for parameter passing.  The order of input terminals and output roots for Mac Methods parallels this.  The leftmost terminal of a Mac Method operation corresponds to the leftmost argument of the Pascal function or procedure, and the rightmost terminal corresponds to the rightmost argument. 

Pascal:

PROCEDURE CopyRgn ( srcRgn, dstRgn: RgnHandle );

Prograph:

 
A Mac Method for a function always returns the value of the function on the leftmost root of the Mac Method.*370*

Pascal:

FUNCTION EqualRgn ( rgnA, rgnB: RgnHandle )  :  Boolean;

Prograph:

Functions and procedures have two different types of parameters:  value parameters and VAR parameters.  VAR parameters are often used as a way of getting extra return values from a function or procedure.  Consequently any VAR parameter present in a Pascal toolbox declaration must have both an input terminal and an output root on the corresponding Mac Method.  The order of VAR parameter output roots is left to right, following any function result. 

Pascal:

FUNCTION SectRect ( src1, src2: Rect;  VAR dstRect: Rect ) : Boolean;

Prograph:

 
A value parameter is passed to a Pascal routine by making a copy of the input argument.  The Pascal routine can only access the copy.  The original data value which is passed as a value parameter is, therefore, never altered. This works out well for Prograph’s dataflow paradigm.  Prograph copies any value parameter before passing it to a Toolbox routine. 

NOTE:  Prograph dereferences any pointers or handles to the correct level of indirection before making the copy.  Also, if an integer or a NULL value is passed to a value parameter expecting a pointer, it is treated as an absolute address. 
A VAR parameter is passed to a Pascal routine by reference (that is, by address). The Pascal routine uses this reference to directly manipulate the input argument.
Sometimes a VAR parameter must contain a valid data value on input to a function or procedure call.  At other times, it is used only as a place holder for data to be output. (You may need to refer to the description of the call in Inside Macintosh to determine which is the case for a particular call.)

If a VAR parameter is not being used for input, you can leave the input terminal unconnected. Prograph will then automatically allocate space for the output.  The GetDateTime routine is an example of this sort of call. 
Pascal:

VAR
  secs : LongInt;
BEGIN
 GetDateTime( secs );
 DoSomething( secs );
END;

Prograph:

 
Other routines require data to be input in a VAR parameter.  The data is altered and returned on the output root.  The UprString routine works in this way.

Pascal:

VAR
 str : Str255;
 diacSens : Boolean;
BEGIN
 str := 'Test String'
 diacSens := TRUE;

 UprString( str, diacSens );
 Show( str );
END;

Prograph:

 
NOTE:  The altering of a data value conflicts with Prograph’s dataflow paradigm. Therefore, Prograph actually makes a copy of an input VAR parameter and passes a reference to the copy. When the call to the Toolbox routine has completed, the copy is passed as an output of the calling operation. 

However, if a pointer is given as the input of a VAR parameter, then no copy is made; the pointer is used as the reference to the input value.  A VAR parameter given a pointer as input returns the same pointer as the output. There is an exception to this:  if the type of the VAR parameter is pointer, then the pointer is treated as a data value, is copied, and the copy (which may, meanwhile, have been incremented) is passed as output of the calling operation.

Prograph handles the GetVol routine in a special way.  Its first parameter, defined in Inside Macintosh as the value parameter StringPtr, is treated in Prograph as a VAR parameter of type Str255.  (It therefore appears as both input and output.)  This definition simplifies the call, making it unnecessary to allocate space before the call or to use the get-string primitive to examine the result.

Toolbox Data Types in Prograph *373*

Macintosh data structures are either simple, compound or array.  A simple type consists of a single data value of the specified type.  A compound type consists of more than one field of the same or different types.  Each field of a compound structure has its own name and may itself be simple, compound or array. An array is a grouping of identical types which share a common name and whose data values are accessed by index. 

Simple Types *374*

The simple Macintosh types which are defined by Prograph are: Boolean, Byte, Handle, Integer, LongInt, Ptr, Real, SignedByte and Unsigned. 
Pascal allows new simple data types to be created from existing simple data types.  When a simple Toolbox type is really the same as an existing simple type, Prograph uses the existing type.  OSType, for instance, is really a renamed LongInt.  Consequently Prograph uses LongInt for all fields and parameters defined in Inside Macintosh as OSType.  Other examples are types OSErr and Style, which Prograph defines as Integer and Byte, respectively.

To facilitate manipulation of data in Macintosh structures, especially generic pointers and handles, all simple Macintosh types are defined as having a single field of that type.  This allows the use of such a field name in the Prograph Mac Get, Set and Address operations.

Compound Types *374*

In Prograph, Macintosh data structures are defined simply as blocks of a certain size.  A GrafPort, for instance, is a block of 108 bytes; the fields of the GrafPort are not part of the structure’s definition. 

NOTE:  The Prograph type string is used interchangeably with the Toolbox type Str255.

The fields of Macintosh structures are defined by type, offset, and size.  Fields are associated with an “owner,” but this is simply a mapping used by the ˙Info… dialog.  Mac Get Field and Mac Set Field operations do not check the type of the structure which is input to them.  These operations simply take the offset and size of the given field and get or set the value of those bytes in the structure.  In the example below, for instance, a pointer to a ParamBlockRec is expected, but any kind of pointer could actually be passed and whatever is found in the two bytes at offset 22 will be returned as an Integer.  Naturally the user can get into trouble very quickly be passing the wrong type of argument. 

Some fields of structures are themselves structures.  For example, the ABusRecord structure has a field called atpAddress which is of type AddrBlock.  An AddrBlock itself has three fields.  To get the value of aNode from an ABusRecord , first get the value of the field atpAddress and then get the value of the field aNode, as shown below.

Setting the value of a field in a nested structure requires an additional step, as shown in the following example.

After getting the value of atpAddress and setting the values of aNode and aSocket therein, it is still necessary to reset the value of atpAddress.  This extra step is needed because the Mac Set Field operations on aNode and aSocket are operating on a copy of the atpAddress field. 

NOTE:  There can be field name conflicts. When a field with the same name, size and offset is referenced by more than one structure, it is entered into the Prograph Macintosh Toolbox field table multiple times, once for each owning structure.  Some fields which are referenced by more than one structure may have different sizes or offsets:  when you type such a field name into a Mac Get/Set/Address operation and hit return, a dialog will be presented to allow you to choose the name of the owning structure.

When a unique field name is required, the assembly-language definition, as shown in Inside Macintosh, is used.  If no assembly language definition exists, or if it is no different from the Pascal definition, the name is changed slightly, usually by prefixing the name with the first one to three letters of the owning structure.  
For example, the FMetricRec structure has four fields that have the same names as, but different sizes and offsets than, fields in the FontInfo structure.  To resolve this conflict, the field ascent is renamed fmAscent, descent is changed to fmDescent, and so on.

These anomalies are few in number, but it’s a good idea to use the ˙Info… dialog to check Toolbox fields before using them.

Arrays *377*

Some Toolbox structures have fields defined as an array of elements of a given type.  For example, the last field of the Macintosh structure TGetRslBlk is called rgRslRec.  It is defined in Pascal as: 

rgRslRec:  ARRAY[1..27] OF TRslRec

In other words rgRslRec consists of 27 TRslRecs, all in a row.

In Prograph, rgRslRec is defined as being of type TRslRec.  Because a TRslRec is 4 bytes in size, the size of the field rgRslRec is shown as 108 bytes(that is, 27 times 4).

There are many structures in which the last field is a variable-length array. It is not known ahead of time how many elements it will contain. 

For example, the last field of TEStyleRec is defined in Pascal as:
runs:  ARRAY[0..0] of StyleRun.

In Prograph, runs is defined as having type StyleRun, with a size of 0.

You can access elements in either type of array by using the indexing feature of the Mac Get Field or Mac Set Field operations.  An optional extra terminal (the second terminal for Get, the third for Set) allows you to provide the index of the element to access. 

NOTE:  Unlike Prograph lists, this index is 0-based, as in most Inside Macintosh Pascal array declarations. 

Certain Toolbox structures have no named fields, but are themselves arrays.  Prograph defines such a structure as having one field with the same name as the structure.  The type of that field is the type of an array element.  It is then possible to use the field name in conjunction with the indexing capability of Mac Get Field and Mac Set Field operations to access the elements of the array.
For example, SFTypeList is defined in Pascal as:
SFTypeList  =  ARRAY[0..3] OF OSType.

In Prograph, SFTypeList is defined as a structure of size 16 bytes.  It has one field, also called SFTypeList, with offset 0 and type LongInt. The following example shows how a pointer of the appropriate size (which could be created using the Macintosh NewPtr call), is fed to a Mac Set operation.  The Prograph list multiplex annotation sets the value at index 0, offset 0 in the Ptr to 'TEXT' and the value at index 1, offset 4 to 'WDBN'.

Note that this mechanism also works with the simple Macintosh types described above. 

TIP:  As in C and Pascal, you can specify file types, creator types, and resource types as four characters delimited by single quotes.  Prograph packs the characters into a LongInt.

Allocating Structures *378*

In most cases, Toolbox structures are created and returned by Toolbox routines.  Sometimes, however, the user must supply the structure.  The low-level File Manager calls, for instance, require as input a pointer to a parameter block that the user must create and initialize. 

To allocate space the Toolbox calls NewHandle and NewPtr are used.  Consult the ˙Info… dialog for the size of each structure.  Remember to call DisposHandle or DisposPtr when finished with the structure.  Prograph will not automatically dispose of Ptrs or Handles which are created by the user or by Macintosh Toolbox calls which the user makes. 

ABlocks, Handles and Pointers *379*

The first entry in the Mac Structs listing of the ˙Info… dialog is the type ABlock.  Cognoscenti will be aware that no such Macintosh type really exists.  The Type ABlock was invented by the implementors of Prograph to facilitate a number of constructs common to languages like Pascal and C but alien to Prograph’s diagrammatic dataflow nature.

ABlock *379*

The type ABlock does double duty.  As ABlock it refers to a variable sized array of bytes which resides with some header information in a Macintosh Handle. 
NOTE:  See the section on “Prograph Data Types” in appendix II, “C Code Usage,” for a complete description of the Prograph data types.

ABlocks are created only by the primitives new-block and read.  Their contents can be manipulated by the Mac Get Field or Mac Set Field operations and the Prograph memory primitives.  If necessary, their handles can be locked and the address of the first data byte can be obtained using the primitives lock-block and block-address.  In this way ABlock may be used simply as a buffer.  Internally, whenever Prograph needs to allocate the equivalent of a local variable to hold a Macintosh structure such as an EventRecord, it actually creates an ABlock whose data size is the same size as an EventRecord.  The type of such a block is changed to EventRecord and will display as such in the value window.

ABlock@ and ABlock@@ *379*

As ABlock@ or ABlock@@, ABlock refers to a place in memory referenced by a generic Macintosh Ptr or Handle.  In addition, pointer and handle types are defined for referencing specific structures.  For instance, a ControlRecord can be referenced by ControlRecord@ or ControlRecord@@.

If a Mac Method expects a pointer to a structure, a handle can be passed and Prograph will dereference it appropriately.  An integer value can also be passed, and will be treated as an absolute address. However, if a handle is expected, a pointer will not do. 

Mac Methods that expect ABlock@ or ABlock@@ also accept pointers and handles to a specific type(such as ControlRecord@ or ControlRecord@@).  Mac Methods that expect pointers or handles to a specific type also accept the generic ABlock@ or ABlock@@.

NOTE:  Any parameter that expects GrafPort@ also accepts CGrafPort@, WindowRecord@, CWindowRecord@, or DialogRecord@.  Also, WindowRecord@ and CWindowRecord@ can be used interchangeably, where appropriate.

Accessing and Dereferencing *380*

Mac Get Field and Mac Set Field operations work with any level of indirection; Prograph does the dereferencing.  Prograph’s memory primitives can also be used to access values.  Most of these primitives (such as put-integer and get-string) accept handles, pointers, integer addresses or ABlocks interchangeably.  You should therefore almost never need to dereference a handle or pointer directly. 

If you do need to dereference, study the following example which, given a handle, makes a pointer.  If the value of the input to from-handle is ABlock@@16#1634F8 then the value of the output of from-handle will be 1455352 (16#1634F8 hexadecimal ) and the value of the output of to-pointer will be ABlock@16#1634F8. 

Function Pointers & Filter Functions *380*

Some Toolbox calls require a pointer to a function as an input parameter.  For instance, by passing a non-NULL value for actionProc to the Toolbox call TrackControl, you can define an action to occur repeatedly while the user holds down the mouse inside a control.  These types of functions are known as filter functions. 

It is not yet possible to write the code for filter functions in Prograph.  It is possible to pass function pointers from Prograph, but only in a limited fashion.

A filter function should be written in C and compiled into a separate code resource.  The code resource should also contain an XPrim which returns the address of the filter function.  From Prograph, you can call the XPrim and pass its output to the Mac Method that requires the function pointer.  (For an example of such a function, see appendix II, “C Code Usage.”) 

BitMaps and PixMaps *381*

There are a number of toolbox calls, such as CopyBits, which should accept either BitMaps or PixMaps (color bitmaps).  These are not pointers or handles, so Prograph’s error checking won’t allow one to be passed in where the other was expected. We have defined six new Mac Methods to work around this problem. They are exactly the same as their “BitMap” counterparts, except that they expect PixMaps as input. The CopyPixBits external primitive which we had previously distributed is no longer necessary.

new function              
base function

CopyPix                            
CopyBits

CopyPixMask                   
CopyMask

SeedPixCFill                   
SeedCFill

CalcPixCMask                 
CalcCMask

CopyDeepPixMask          
CopyDeepMask

PixMapToRegion
             BitMapToRegion